home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 301-325 / disk_313 / uucp / uucp1.lzh / src / uucico / uucico.c < prev    next >
C/C++ Source or Header  |  1990-01-25  |  33KB  |  1,462 lines

  1.  
  2. /*
  3.  *  UUCICO.C
  4.  *
  5.  *  (C) Copyright 1987 by John Gilmore.
  6.  *  Copying and use of this program are controlled by the terms of the Free
  7.  *  Software Foundation's GNU Emacs General Public License.
  8.  *
  9.  *  Derived from:
  10.  *  i[$]uuslave.c     1.7 08/12/85 14:04:20
  11.  *  which came from the ACGNJ BBS system at +1 201 753 9758.  Original
  12.  *  author unknown.
  13.  *
  14.  *  Ported to Amiga by William Loftus
  15.  *  Amiga Changes Copyright 1988 by William Loftus.  All rights reserved.
  16.  *  Additional Major Changes (c)Copyright 1989 by Matthew Dillon, All rights reserved
  17.  *
  18.  * 14-Oct-89, moved modem_init() to before poll_sys.
  19.  *
  20.  * -r option    (-r1 does a call out to all systems we have mail for)
  21.  * -D[EVICE] dev    sets serial device name (automatic from Getty)
  22.  * -U[NIT] unit     sets unit name (automatic from Getty)
  23.  * -h0            Ignore CD (carrier detect)
  24.  */
  25.  
  26. #include "/version.h"
  27.  
  28. #include "includes.h"           /* System include files, system dependent */
  29. #include "uucp.h"               /* Uucp definitions and parameters */
  30. #include "sysdep.h"             /* System dependent parts of gnuucp */
  31. #include "modem.h"              /* Modem commands */
  32. #include <log.h>
  33. #include <tmpfile.h>
  34.  
  35. int sigint();
  36. void modem_init();
  37. void cleanup();
  38.  
  39. #define MAX_FLAGS    40
  40.  
  41. extern int errno;
  42.  
  43. IDENT(".06");
  44.  
  45. static char *Copyright = COPYRIGHT;
  46.  
  47. char    ttynam[NAMESIZE],        /* Name of tty we use as serial port */
  48.     srcnam[NAMESIZE],        /* Source file name */
  49.     dstnam[NAMESIZE],        /* Dest file name */
  50.     who[NAMESIZE] = "-",            /* Who sent the file */
  51.     flags[MAX_FLAGS],        /* Flags from file xfer cmd */
  52.     temp[NAMESIZE];         /* Temp file name */
  53.  
  54. int    ourpid = 0,            /* Our process ID */
  55.     ignore_time_restrictions = 0,    /* Call out even if L.sys sez no */
  56.     mode;                /* File mode from file xfer cmd */
  57.  
  58. char  host_name[MAX_HOST] = "AmigaUUCP";  /* Other guy's host name */
  59. char  our_name[MAX_HOST];    /* Our uucp hostname, set from usenet.ctl */
  60. char  path[128];
  61. int   debug   = -1;    /* -1 indicates not set by command line or ctl file */
  62. int   f_wait  = 0;    /* wait for a call (-w) or calls (-w -e) after outbnd */
  63. int   loop    = 0;    /* Loop accepting logins if tty name specified */
  64. int   curtemp = 0;
  65. int   Overide = 0;    /* overide modem protocol        */
  66. int   Getty   = 0;    /* -Getty initiated            */
  67. int   IgnoreCD= 0;    /* xgetc() should ignore carrier?   */
  68. int   OurNameOv= 0;
  69. int   WindowOne= 0;
  70.  
  71. #define MAX_STRING    200    /* Max length string to send/expect */
  72.  
  73. #define MSGO2IDX    7
  74.  
  75. /* We print these prompts */
  76.  
  77. char msgo0[] = "login: ";
  78. char msgo1[] = "Password:";
  79. char msgo2[10+MAX_HOST] = { "\20Shere" };   /*  NO =    */
  80. char msgo3[] = "\20ROK\0";
  81. char msgo3a[]= "\20P";
  82. char msgo3b[]= "\20Pg\0";
  83. char msgo4[] = "\20OOOOOOO\0";
  84.  
  85. /* We expect to receive these strings */
  86.  
  87. char msgi0[] = "uucp\r";
  88. char msgi1[] = "s8000\r";
  89. /* char msgi2[] = "\20S*\0"; We now scan it specially FIXME */
  90. char msgi3[] = "\20Ug\0";
  91. char msgi4[] = "OOOOOO";
  92.  
  93. #define SPOOLDIR "UUSPOOL:"
  94.  
  95. /*
  96.  * Protocol switch data structure
  97.  */
  98.  
  99. extern int gturnon(), grdmsg(), gwrmsg(), grddata(), gwrdata(), gturnoff();
  100.  
  101. #define turnon    gturnon
  102. #define rdmsg    grdmsg
  103. #define wrmsg    gwrmsg
  104. #define rddata    grddata
  105. #define wrdata    gwrdata
  106. #define turnoff gturnoff
  107.  
  108. int
  109. getname(isshere)
  110. {
  111.     int data, count = 0;
  112.     static char msgi[MAX_STRING+SLOP];    /* Incoming trash buffer */
  113.  
  114.     /* Read data until null character */
  115.  
  116.     while ((data = xgetc(BYTE_TO)) != EOF) {
  117.     data &= 0x7F;
  118.     if (data == 020)
  119.         break;
  120.     }
  121.     if (data == EOF)
  122.     return FAIL;
  123.  
  124.     while ((data = xgetc(BYTE_TO)) != EOF && (data & 0x7F)) {
  125.     data &= 0x7F;
  126.     if (count == 0 && data != 'S')
  127.         continue;
  128.     if (count > sizeof(msgi) - 2)
  129.         continue;
  130.     msgi[count++] = (char)data;
  131.     }
  132.     msgi[count] = 0;
  133.  
  134.     if (debug > 8)
  135.     printf("GETNAME MSG (%d): %s\n", count, msgi);
  136.  
  137.     if (msgi[0] != 'S')
  138.     return FAIL;
  139.     if (isshere) {
  140.     for (count = 1; msgi[count] && msgi[count] != '='; ++count);
  141.     if (msgi[count] == '=')
  142.         ++count;
  143.     } else {
  144.     count = 1;
  145.     }
  146.     if (msgi[count]) {
  147.     if (debug > 8)
  148.         printf("Compare host names: '%s' '%s'\n", host_name, msgi + count);
  149.     strcpy (host_name, msgi + count);
  150.     }
  151.     strtok(host_name, " ");     /*  put \0 after hostname */
  152.     if (debug > 8)
  153.     printf("Hostname is '%s'\n", host_name);
  154.     return SUCCESS;
  155. }
  156.  
  157. /*
  158.  *  get_proto() checks the list of protos given by the foriegn machine
  159.  *  checking for 'g' (which is the only proto we have).  Use only in master
  160.  *  mode.
  161.  */
  162.  
  163. int
  164. get_proto()
  165. {
  166.     int data;
  167.  
  168.     while ((data = xgetc(BYTE_TO)) != EOF) {
  169.     data &= 0x7F;
  170.     if (data == 0)
  171.         break;
  172.     if (data == 'g')
  173.         return(SUCCESS);
  174.     }
  175.     return FAIL;
  176. }
  177.  
  178. /*
  179.  * Medium level input routine.
  180.  *
  181.  * Look for an input string for the send-expect sequence.
  182.  * Return 0 for matching string, 1 for timeout before we found it.
  183.  * FIXME:  we only time out if the other end stops sending.  If it
  184.  *       keeps sending, we keep listening forever.
  185.  */
  186.  
  187. instr(s, n)
  188. char *s;
  189. int n;
  190. {
  191.     int data,count,j;
  192.     int i;
  193.     static char msgi[512];  /* Incoming trash buffer */
  194.  
  195.     count = 0;
  196.  
  197.     if (debug > 8) {
  198.     printf("Expecting ");
  199.     for (i = 0; i < n; i++)
  200.         printc(s[i]);
  201.     printf("\n");
  202.     }
  203.  
  204.     while ((data = xgetc(BYTE_TO)) != EOF) {
  205.     msgi[count++] = (char)data & 0x7F;
  206.  
  207.     if (count == sizeof(msgi)) {    /*  throw away first half */
  208.         count = sizeof(msgi) / 2;
  209.         bcopy(msgi + sizeof(msgi) / 2, msgi, sizeof(msgi) / 2);
  210.     }
  211.  
  212.     if (count >= n) {
  213.         for (i = n - 1, j = count - 1; i >= 0; i--, j--) {
  214.         if (*(s+i) != msgi[j])
  215.             break;
  216.         }
  217.         if (i < 0) {
  218.         if (debug > 8)
  219.             printf("\n");
  220.         return(0);
  221.         }
  222.     }
  223.     }
  224.  
  225.     if (debug > 8)
  226.     printf("\n");
  227.     msgi[count] = (char)0;
  228.     return(1);
  229. }
  230.  
  231. /*
  232.  * Debugging hack for stuff written to the modem.
  233.  */
  234.  
  235. int
  236. twrite(s, n)
  237. char *s;
  238. int  n;
  239. {
  240.     int i;
  241.  
  242.     if (debug > 8) {
  243.     printf("Wrote:  ");
  244.     for (i = 0; i < n; i++)
  245.         printc(s[i]);
  246.     printf("\n");
  247.     }
  248.     return xwrite(s, n);
  249. }
  250.  
  251.  
  252. /*
  253.  * MAIN ROUTINE.
  254.  *
  255.  * This is called at program startup.  It parses the arguments to the
  256.  * program (if any) and sets up to receive a call on the modem.
  257.  *
  258.  * If there are no arguments, we assume the caller is already on standard
  259.  * input, waiting to do uucp protocols (past the login prompt), and we
  260.  * just handle one caller.
  261.  *
  262.  * If there is an argument, it is the name of the tty device where we
  263.  * should listen for multiple callers and handle login and password.
  264.  */
  265.  
  266. void
  267. main(argc,argv)
  268. int argc;
  269. char *argv[];
  270. {
  271.     int     i;
  272.     char    *poll_sys = (char *)NULL;   /* System name to poll, or none */
  273.     short   rmode = 0;            /* 1 = master, 0 = slave    */
  274.  
  275.     LogProgram = "uucico";
  276.     LogHost = host_name;
  277.     LogWho  = who;
  278.  
  279.     signal(SIGINT,sigint);  /* Allow the user to break */
  280.  
  281.     /* FIXME, use getopt */
  282.     /* scan command line arguments, kinda kludgy but it works */
  283.  
  284.     for (i = 1; i < argc; ++i) {
  285.     if (argv[i][0] != '-') {
  286.         printf("uucico: warning, extra args ignored: %s\n", argv[i]);
  287.         break;
  288.     }
  289.     switch (argv[i][1]) {
  290.     case 'N':
  291.         strcpy(our_name, argv[i] + 2);
  292.         OurNameOv = 1;
  293.         break;
  294.     case 'D':       /*  Serial Device   */
  295.         {
  296.         extern char *DeviceName;
  297.         DeviceName = argv[++i];
  298.         }
  299.         break;
  300.     case 'U':       /*  Serial Unit     */
  301.         {
  302.         extern long DeviceUnit;
  303.         DeviceUnit = atoi(argv[++i]);
  304.         }
  305.         break;
  306.     case 'g':
  307.     case 'G':
  308.         Getty = 1;
  309.         break;
  310.     case 'h':
  311.         IgnoreCD = atoi(argv[i] + 2);
  312.         break;
  313.     case 'w':
  314.         ++f_wait;
  315.         break;
  316.     case 'r':
  317.         rmode = atoi(&argv[i][2]);
  318.         break;
  319.     case 'x':
  320.         debug = atoi(&argv[i][2]);
  321.         LogLevel = debug;
  322.         LogToStdout = 1;
  323.         printf("uucico: debug level set to %d\n", debug);
  324.         break;
  325.     case 'o':
  326.         Overide = 1;
  327.         break;
  328.     case 'n':
  329.         WindowOne = 1;  /*    force windowing mode to size=1     */
  330.         break;
  331.     case 'S':
  332.         ignore_time_restrictions++;
  333.     case 's':
  334.         poll_sys = &argv[i][2];
  335.         break;
  336.     case 'e':
  337.         ++loop;
  338.         break;
  339.     /* Is -t needed for MSDOS?  Why?  -- hoptoad!gnu */
  340.     case 't':
  341.         curtemp++;
  342.         printf("uucico: using ~uutemp.$$$ for temp file\n");
  343.         break;
  344.     default:
  345.         printf("uucico: warning, bad flag %s\n", argv[i]);
  346.         break;
  347.     }
  348.     }
  349.  
  350.     /* If argument provided, use it as name of comm port */
  351.  
  352.     /* FIXME, this needs some thought. */
  353.  
  354.     getcwd(path,128);
  355.     if (chdir(SPOOLDIR)) {
  356.     perror("Can't chdir to Spool directory");
  357.     exit(2);
  358.     }
  359.  
  360.     read_ctl();             /* Read control file FIXME */
  361.  
  362.     /*
  363.      * If running via getty/login, our debug stdout had better
  364.      * go to a file, not to the usual stdout!
  365.      */
  366.  
  367.     if (debug > 0 && Getty) {
  368.     freopen("T:uuslave.log", "a", stdout);
  369.     }
  370.  
  371.     setvbuf(stdout, NULL, _IOLBF, 0);
  372.  
  373.     /* Timestamp the long debug log */
  374.  
  375.     if (debug > 0) {
  376.     long clock;
  377.  
  378.     time(&clock);
  379.     printf("\014\nuuslave log on tty '%s' starting %s\n",
  380.         ttynam, ctime(&clock));
  381.     }
  382.  
  383.     /* Log our presence so we humans reading the logs can find the
  384.        entries created by uuslave. */
  385.  
  386.     ulog(-1, "Startup %s", VERSION);
  387.  
  388.     amiga_setup();
  389.  
  390.     modem_init();
  391.  
  392.     if (poll_sys) {
  393.     if (*poll_sys == '\0')
  394.         poll_sys = (char *)NULL;
  395.     call_system(poll_sys);
  396.     if (!f_wait)
  397.         goto end;
  398.     } else {
  399.     if (rmode) {
  400.         do_outbound();
  401.         if (!f_wait)
  402.         goto end;
  403.     }
  404.     }
  405.  
  406.     do {
  407.     /*
  408.      *  Set up serial channel, wait for incoming call.
  409.      */
  410.     DEBUG(0, "\nRestarting\n", 0);
  411.  
  412.     if (Getty == 0 && Overide == 0)
  413.         openline();
  414.  
  415.     do_session(Getty);
  416.  
  417.     hangup();
  418.     DEBUG(0, "\nEnd of call\n", 0);
  419.     } while (loop && !Getty);
  420.  
  421. end:
  422.     cleanup();
  423. }
  424.  
  425. /*
  426.  * translate embedded escape characters
  427.  */
  428.  
  429. void
  430. xlat_str(msg, out)
  431. char    *msg;
  432. char    *out;
  433. {
  434.     int i  = 0;
  435.     int cr = 1;
  436.     /*int j  = 0;*/
  437.  
  438.     while (msg[i]) {
  439.     if (msg[i] == '\\') {
  440.         switch (msg[++i]) {
  441.         case 'r':            /* carriage return */
  442.         twrite("\r", 1);
  443.         /*out[j++] = 0x0d;*/
  444.         break;
  445.         case 'n':            /* line feed */
  446.         twrite("\n", 1);
  447.         /*out[j++] = 0x0a;*/
  448.         break;
  449.         case '\\':           /* back slash */
  450.         twrite("\\", 1);
  451.         /*out[j++] = '\\';*/
  452.         break;
  453.         case 't':            /* tab */
  454.         twrite("\t", 1);
  455.         /*out[j++] = '\t';*/
  456.         break;
  457.         case 'b':
  458.         SendBreak();
  459.         break;
  460.         case 'd':            /* delay */
  461.         Delay(180);
  462.         break;
  463.         case 's':            /* space */
  464.         twrite(" ", 1);
  465.         /*out[j++] = ' ';*/
  466.         break;
  467.         case 'c':            /* no CR at end */
  468.         cr = 0;
  469.         break;
  470.         default:        /* don't know so skip it */
  471.         break;
  472.         }
  473.         ++i;
  474.     } else {
  475.         twrite(msg + i, 1);
  476.         ++i;
  477.         /*out[j++] = msg[i++];*/
  478.     }
  479.     }
  480.     if (cr) {
  481.     twrite("\r", 1);
  482.     /*out[j++] = 0x0d;*/
  483.     }
  484.     /*out[j] = '\0';*/
  485. }
  486.  
  487. /*
  488.  * Read the control file and grab a few parameters.
  489.  */
  490.  
  491. read_ctl()
  492. {
  493.     FILE  *fd;
  494.     static char buf[MAX_CTLLINE];
  495.  
  496.     if (!(fd = fopen("UULIB:Config", "r"))) {
  497.     printf("Can't Find config file");
  498.     chdir(path);
  499.     exit(3);
  500.     }
  501.  
  502.     /* find path to inbound news */
  503.  
  504.     while (NULL != fgets(buf, sizeof buf, fd)) {
  505.     if (strncmp(buf, "NodeName", 8) == 0) {
  506.         if (OurNameOv == 0)
  507.         strcpy(our_name, strtok(&buf[9], CTL_DELIM) ) ;
  508.     } else if (strncmp(buf, "Debug", 5) == 0)
  509.         if (debug < 0)
  510.         debug = atoi(strtok(&buf[6], CTL_DELIM));
  511.     }
  512.     fclose(fd);
  513.     return (1);
  514. }
  515.  
  516. /*
  517.  * Search spool queues for work, call the systems we need to call.
  518.  */
  519.  
  520. do_outbound()
  521. {
  522.     return call_system((char *)NULL);
  523. }
  524.  
  525. /*
  526.  * Call a specific system, or all systems that have work pending.
  527.  */
  528.  
  529. call_system(sys)
  530. char    *sys;
  531. {
  532.     FILE    *lsys;
  533.     static char buf[MAX_LSYS];
  534.     static char sysnam[MAX_HOST];
  535.     static char prev_name[MAX_HOST];
  536.     int     called = FAIL;
  537.  
  538.     /*
  539.      * Unix uucico just reads the directory, and calls the systems
  540.      * in the order of the files in the directory.  We want more
  541.      * control than that, though I'm not sure that L.sys order is
  542.      * best either.  For example, in the first call after 11PM,
  543.      * I'd like to call the sites that haven't been callable before
  544.      * 11PM first, and finish up with the ones I've been able to call
  545.      * all day.  FIXME.
  546.      */
  547.  
  548.     if (! (lsys = fopen("UULIB:L.sys", "r"))) {
  549.         DEBUG(0, "uucico: can't open L.sys, errno %d\n", errno);
  550.         return 0;
  551.     }
  552.     sysnam[0] = '\0';               /* Initially, no previous sys */
  553.  
  554.     /* Once per system in L.sys... */
  555.     /* FIXME, handle continuation lines (trailing "\") */
  556.  
  557.     while (fgets(buf, sizeof buf, lsys)) {
  558.     if (buf[0] == '#' || buf[0] == '\n')
  559.         continue;
  560.  
  561.     /*
  562.      * Grab the system name.  If same as previous, and
  563.      * the previous call worked, skip it.
  564.      */
  565.  
  566.     strcpy(prev_name, sysnam);
  567.     (void) sscanf(buf, "%s", sysnam);
  568.     if (!strcmp(sysnam, prev_name)) {
  569.         if (called == SUCCESS)
  570.         continue;
  571.     }
  572.  
  573.     /*
  574.      * If a system name was specified, skip til we find it
  575.      * If none was specified, only call if there is work.
  576.      */
  577.  
  578.     if (sys) {
  579.         if (strcmp(sys, sysnam) != 0)
  580.         continue;
  581.     } else {
  582.         DEBUG(3,"searching for outbound to %s\n", sysnam);
  583.         if (!work_scan(sysnam)) {
  584.         DEBUG(3,"no work for %s\n", sysnam);
  585.         called = SUCCESS;    /* Don't try further */
  586.         continue;
  587.         }
  588.         DEBUG(2, "uucico: found work for %s\n", sysnam);
  589.     }
  590.  
  591.     called = call_sysline(buf);
  592.  
  593.     if (called == SUCCESS && sys)
  594.         break;
  595.     }
  596.  
  597.     fclose(lsys);
  598.     if (called == FAIL && sys)
  599.     DEBUG(0, "Could not call system %s\n", sys);
  600.     return 0;
  601. }
  602.  
  603. /*
  604.  *  Call out to a system, given its L.sys line.
  605.  */
  606.  
  607. call_sysline(lsysline)
  608. char *lsysline;
  609. {
  610.     static char    tempname[MAX_HOST + 30 + SLOP];
  611.     static char    strbuf[MAX_STRING+SLOP];
  612.     char    *sysnam,
  613.         *times,
  614.         *acu,
  615.         *sbaud,
  616.         *telno,
  617.         *send,
  618.         *expct;
  619.     int     baud;
  620.  
  621.     who[0] = '-'; who[1] = '\0';    /* No user now (for logit) */
  622.  
  623.     /* FIXME, use the values it is ignoring here */
  624.  
  625.     sysnam = strtok(lsysline, " ");
  626.     times =  strtok(NULL, " ");   /* Time */
  627.     acu =    strtok(NULL, " ");     /* ACU */
  628.     sbaud =  strtok(NULL, " ");   /* Baud */
  629.     telno =  strtok(NULL," ");    /* phone */
  630.  
  631.     strcpy(host_name, sysnam);
  632.  
  633.     if ((!ignore_time_restrictions) && (strcmp(times,"Any"))) {
  634.     /* FIXME, check the time parameter and return FAIL if
  635.      * it does not allow calls now.  Meanwhile, bounce
  636.      * all calls unless -S is specified. */
  637.     ulog(-1, "Wrong Time To Call %s", sysnam);
  638.     return FAIL;
  639.     }
  640.  
  641.     baud = atoi(sbaud);
  642.  
  643.     /*    FIX ME, acu not implemented ?    */
  644.     DEBUG(4, "Opening outgoing line %s\n", acu);
  645.     if (openout(acu, baud) != SUCCESS)
  646.     return FAIL;
  647.  
  648.     if (Overide == 0) {
  649.     if (dial_nbr(telno)) {
  650.         ulog(-1, "FAILED call to %s", host_name);
  651.         return FAIL;
  652.     }
  653.     }
  654.  
  655.     /* FIXME, log tty, baud rate, ... */
  656.     ulog(-1, "DIALED %s", host_name);
  657.  
  658.     /*
  659.      * Process send-expect strings.
  660.      * FIXME, deal with "-", BREAK, etc.
  661.      */
  662.  
  663.     while (send = (char*)strtok((char *)NULL, " ")) {
  664.     if (send[0] != '"' || send[1] != '"' || send[2] != '\0') {
  665.         if (instr(send, strlen(send)))
  666.             goto bort1;
  667.     }
  668.  
  669.     if (expct = (char*)strtok((char *)NULL, " ")) {
  670.         /* FIXME secondary strings, e.g. ogin:-EOT-ogin: */
  671.         xlat_str(expct, strbuf);
  672.  
  673.         /*twrite(strbuf, strlen(strbuf));*/
  674.     }
  675.     }
  676.  
  677.     /*
  678.      * FIXME, there should be a way to detect login/passwd
  679.      * failure here and keep doing the script rather than
  680.      * continuing to expect Shere at another login: prompt.
  681.      */
  682.  
  683.     ulog(-1, "SUCCEEDED call to %s", host_name);
  684.  
  685.  
  686.     if (getname(1))         /*  get name        */
  687.     goto bort1;
  688.                 /*    send response    */
  689.     sprintf(tempname, "\20S%s -Q0 -x%d\0", our_name, debug);
  690.     twrite(tempname, strlen(tempname)+1); /* Including null */
  691.  
  692.     /* wait for ok message, wait for protocol request
  693.      * send protocol 'g' response */
  694.     /* FIXME, we don't actually wait for the ROK message, since
  695.      * it is immediately followed by the Pprotos message.  We
  696.      * currently just look for a Pg message.  This needs work.
  697.      * FIXME, WE CAN'T TALK TO SITES THAT SUPPORT more than 'g'.
  698.      */
  699.  
  700.     if (instr(msgo3a, sizeof(msgo3a)-1)) {
  701.     if (!get_proto())
  702.        goto bort1;
  703.     }
  704.  
  705.  
  706.     twrite( msgi3, sizeof(msgi3)-1);
  707.  
  708.     if (turnon(1))
  709.     goto bort1;
  710.  
  711.     ulog(-1, "OK Startup");
  712.  
  713.     top_level(1);
  714.     hangup();
  715.     return SUCCESS;
  716.  
  717. bort1:
  718.     hangup();
  719.     return FAIL;
  720. }
  721.  
  722. /* Handle a single uucp [slave] login session */
  723.  
  724. do_session(ontheline)
  725. int ontheline;
  726. {
  727.     if (ontheline == 0) {
  728.     /* output login request, verify uucp */
  729.     twrite(msgo0,sizeof(msgo0)-1);
  730.     if (instr(msgi0,sizeof(msgi0)-1)) {
  731.         printf("uucico: invalid login name\n");
  732.         goto bort;
  733.     }
  734.  
  735.     /* output password request, verify s8000 */
  736.     twrite(msgo1,sizeof(msgo1)-1);
  737.     if (instr(msgi1,sizeof(msgi1)-1)) {
  738.         printf("uucico: invalid password\n");
  739.         goto bort;
  740.     }
  741.  
  742.     printf("uucico: correct login\n");
  743.     }
  744.  
  745.     /*
  746.      *    send Shere=<myhost>
  747.      *
  748.      *    Apparently mac UUCP has a bug that only allows 7
  749.      *    char host names, and it fails if it gets shere=<myhost>
  750.      *    where <myhost> is > 7 chars.
  751.      */
  752.  
  753.     /*strcpy(msgo2 + MSGO2IDX, our_name);*/
  754.     twrite(msgo2,strlen(msgo2)+1);
  755.  
  756.     /*
  757.      *    get \020S<host> -Qn n    (??)
  758.      */
  759.  
  760.     if (getname(0))
  761.     goto bort;
  762.  
  763.     /* output ok message, output protocol request, wait for response */
  764.  
  765.     twrite(msgo3,sizeof(msgo3)-1);
  766.  
  767.     /* FIXME, make the protocol list here, and use it */
  768.     twrite(msgo3b,sizeof(msgo3b)-1);
  769.     if (instr(msgi3,sizeof(msgi3)-1))
  770.         goto bort;
  771.  
  772.     if (turnon(0))
  773.     goto bort;
  774.  
  775.     ulog(-1, "OK Startup");
  776.     top_level(0);
  777.  
  778. bort:
  779.     if (debug > 0)
  780.     printf("uucico: call complete\n");
  781.     return (1);
  782. }
  783.  
  784. /*
  785.  * Handle transactions "at top level", as Unix uucp's debug log says.
  786.  *
  787.  * As master, we scan our queues for work and send requests to the
  788.  * other side.    When done, we send a hangup request and switch to slave mode.
  789.  *
  790.  * As slave, we accept requests from the other side; when it is done,
  791.  * it sends a hangup request, and we switch to master mode, if we have
  792.  * any work queued up for that system.
  793.  *
  794.  * This repeats as long as either side has work to do.    When all the
  795.  * queued work is done, we agree to hang up, terminate the packet protocol,
  796.  * and return to the caller.  (We still haven't hung up the phone line yet.)
  797.  *
  798.  * A curious feature of the hangup protocol is that it is not a simple
  799.  * question-answer.  The master says "H", asking about hangup.  The
  800.  * slave responds "HY" saying OK.  The master then says "HY" also,
  801.  * then both of them hang up.  Maybe this is to make sure the first HY
  802.  * got ack'ed?  Anyway, an "H" is reported as HANGUP and an "HY" as
  803.  * HANGNOW.  After we send an HY, we go back to listening for commands;
  804.  * if the master sends something other than HY, we'll do it.
  805.  */
  806.  
  807. #define HANGUP    2        /* Signal to switch master/slave roles */
  808. #define HANGNOW 3        /* Signal to hang up now */
  809. #define COPYFAIL    4    /* File copy failed */
  810.  
  811. int
  812. top_level(master_mode)
  813. int master_mode;
  814. {
  815.     static char    buf[MAXMSGLEN];       /* For hangup responses */
  816.  
  817.     if (master_mode) {
  818.     (void) work_scan(host_name);    /* Kick off queue scan */
  819.     goto master;
  820.     }
  821.  
  822.     for (;;) {
  823.     slave:            /*  SLAVE SIDE    */
  824.     for (;;) {
  825.         DEBUG(4, "*** TOP *** - slave\n", 0);
  826.         switch (do_one_slave()) {
  827.         case SUCCESS:
  828.         break;
  829.         case FAIL:
  830.         return FAIL;
  831.         case HANGUP:
  832.         if (work_scan(host_name)) {
  833.             if (wrmsg("HN"))
  834.             return FAIL;
  835.             goto master;
  836.         } else {
  837.             if (wrmsg("HY"))
  838.             return FAIL;
  839.             break;    /*  go to master mode */
  840.         }
  841.         case HANGNOW:
  842.         goto quit;
  843.         }
  844.     }
  845.     master:    /*  MASTER SIDE */
  846.     for (;;) {
  847.         DEBUG(4, "*** TOP *** - master\n", 0);
  848.         switch (do_one_master()) {
  849.         case SUCCESS:
  850.         break;
  851.         case FAIL:
  852.         return FAIL;
  853.         case HANGUP:
  854.         /* We wrote an H command, what's the resp? */
  855.         if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
  856.             return FAIL;
  857.         }
  858.         if (buf[0] != 'H')
  859.             return FAIL;
  860.         if (buf[1] == 'N')
  861.             goto slave;
  862.         else {
  863.             /* Write the final HY */
  864.             if (wrmsg("HY"))
  865.             return FAIL;
  866.             goto quit;
  867.         }
  868.         }
  869.     }
  870.     }
  871.  
  872. quit:
  873.     /* Shut down the packet protocol */
  874.  
  875.     turnoff();
  876.  
  877.     /* Write the closing sequence */
  878.  
  879.     twrite(msgo4, sizeof(msgo4)-1);
  880.     (void) instr(msgi4, sizeof(msgi4)-1);
  881.  
  882.     twrite(msgo4, sizeof(msgo4)-1);
  883.  
  884.     strcpy(who, "-");
  885.     ulog(-1, "OK Conversation complete");
  886.  
  887.     return SUCCESS;   /* Go byebye */
  888. }
  889.  
  890. /*
  891.  * We are slave; get a command from the other side and execute it.
  892.  *
  893.  * Result is SUCCESS, FAIL, HANGUP, or HANGNOW.
  894.  */
  895.  
  896. int
  897. do_one_slave()
  898. {
  899.     static char msg[MAXMSGLEN];        /* Master's message to us */
  900.  
  901.     /* Get master's command */
  902.     if (rdmsg(msg, MAXMSGLEN) != SUCCESS)
  903.     return FAIL;
  904.  
  905.     /* Print it for easy debugging */
  906.     DEBUG(5,"\nCommand: %s\n\n", msg);
  907.  
  908.     switch (msg[0]) {
  909.     case 'S':
  910.     if (msg[1] != ' ')
  911.         break;
  912.     return host_send_file(msg);
  913.     case 'R':
  914.     if (msg[1] != ' ')
  915.         break;
  916.     return host_receive_file(msg);
  917.     case 'X':
  918.     /*
  919.      * Cause uuxqt to run (on certain files?)
  920.      * See Protocol.doc for sketchy details.
  921.      */
  922.     break;
  923.     case 'H':
  924.     if (msg[1] == '\0') return HANGUP;
  925.     if (msg[1] == 'Y')  return HANGNOW;
  926.     if (msg[1] == 'N')  return SUCCESS;     /* Ignore HN to slave */
  927.     break;
  928.     }
  929.  
  930.     /* Unrecognized packet from the other end */
  931.  
  932.     DEBUG(0, "Bad control packet refused: %s\n", msg);
  933.     if (yesno(msg[0], 0, 0))        /* FIXME: return error code */
  934.     return FAIL;
  935.     return SUCCESS;
  936. }
  937.  
  938. /*
  939.  *  Do one piece of work as master.
  940.  *
  941.  *  FIXME:  we don't handle the flags, e.g. -c, properly!
  942.  *
  943.  *  Now only dequeues queue file if all transfers were successful.
  944.  */
  945.  
  946. int
  947. do_one_master()
  948. {
  949.     FILE    *fd;
  950.     char    *sname;
  951.     char    cmnd[1];            /* Command character */
  952.     static char buf[256];
  953.     int     fail = SUCCESS;
  954.     int     failaccum = 0;
  955.     int     num;
  956.     int     delmeflag;
  957.     static char notify[NAMESIZE];   /* A bit large...FIXME */
  958.     char    *delList[16];        /* delete files list   */
  959.     short   di = 0;
  960.  
  961.     /* FIXME: do the notify stuff */
  962.  
  963.     sname = work_next();
  964.     if (!sname) {
  965.     /* No more work, time to hang up. */
  966.     if (wrmsg("H"))
  967.         return FAIL;
  968.     return HANGUP;
  969.     }
  970.  
  971.     DEBUG(2, "Request file %s\n", sname);
  972.  
  973.     LockFile(sname);
  974.  
  975.     fd = fopen(sname, "r");
  976.     if (fd == NULL) {
  977.     UnLockFile(sname);
  978.     DEBUG(0, "uucico: couldn't open %s\n", sname);
  979.     return SUCCESS;
  980.     }
  981.  
  982.     while (fgets(buf, sizeof buf, fd)) {
  983.     DEBUG(3, "Queued request: %s", buf);
  984.  
  985.     if (buf[1] != ' ')
  986.         goto badnum;
  987.  
  988.     num = sscanf(buf, "%s %s %s %s %s %s %o\n",
  989.         cmnd, srcnam, dstnam, who, flags, temp, &mode, notify
  990.     );
  991.  
  992.     switch (cmnd[0]) {
  993.     case 'S':
  994.         if (num < 7 || num > 8)
  995.         goto badnum;
  996.         fail = local_send_file(buf, &delmeflag);
  997.         if (delmeflag) {
  998.         if (di == sizeof(delList)/sizeof(delList[0])) {
  999.             ulog(-1, "Too many source files in Cmd file! %s", sname);
  1000.         } else {
  1001.             delList[di] = malloc(strlen(temp) + 1);
  1002.             strcpy(delList[di], temp);
  1003.             ++di;
  1004.         }
  1005.         }
  1006.         break;
  1007.     case 'R':
  1008.         if (num != 5)
  1009.         goto badnum;
  1010.         fail = local_receive_file(buf);
  1011.         break;
  1012.     default:
  1013.     badnum:
  1014.         DEBUG(0, "Unknown/invalid queued request: %s\n", buf);
  1015.         ++fail;
  1016.         break;
  1017.     }
  1018.     if (fail != SUCCESS)
  1019.         ++failaccum;
  1020.  
  1021.     /* FIXME, what does uucp do if one of N xfers fails? */
  1022.  
  1023.     if (fail == FAIL) {
  1024.         ulog(-1, "Error in work file %s", sname);
  1025.         ulog(-1, "Bad line is: %s", buf);
  1026.     }
  1027.     }
  1028.     fclose(fd);
  1029.  
  1030.     /*
  1031.      *    If we successfuly copied everything zap the queue file
  1032.      *    and any local data files...
  1033.      */
  1034.  
  1035.     if (failaccum == 0) {
  1036.     while (di) {
  1037.         --di;
  1038.         remove(delList[di]);
  1039.         free(delList[di]);
  1040.     }
  1041.     fail = remove(sname);
  1042.     UnLockFile(sname);
  1043.     if (fail != 0) {
  1044.         ulog(-1, "Unable to remove work file %s", sname);
  1045.         DEBUG(0, "Can't remove, errno %d\n", errno);
  1046.     } else {
  1047.         DEBUG(4, "Removed work file %s\n", sname);
  1048.     }
  1049.     } else {
  1050.     UnLockFile(sname);
  1051.     }
  1052.     return SUCCESS;
  1053. }
  1054.  
  1055. /* Send a "yes or no" packet with character 'c'. */
  1056.  
  1057. int
  1058. yesno(c, true, err)
  1059. char c;
  1060. int true;
  1061. int err;
  1062. {
  1063.     char buf[21];
  1064.  
  1065.     buf[0] = c;
  1066.     buf[1] = true? 'Y': 'N';
  1067.     buf[2] = 0;
  1068.     if (err && !true)
  1069.     sprintf(buf+2,"%d", err);
  1070.  
  1071.     return wrmsg(buf);
  1072. }
  1073.  
  1074. /*
  1075.  *  SLAVE MODE, Master wishes to send a file to us
  1076.  *
  1077.  *  SECURITY:    If file is not in list of allowed directories
  1078.  *        disallow transfer.  UUSPOOL:   is always in the
  1079.  *        list.
  1080.  *
  1081.  *        If file is for UUSPOOL: (the current dir), disallow "C." files
  1082.  *        NOTE: success return and file redirected to T: as this can
  1083.  *        occur only if somebody purposefully is trying to break us.
  1084.  *
  1085.  *  Return 0 = success
  1086.  */
  1087.  
  1088. int
  1089. host_send_file(msg)
  1090. char  *msg;
  1091. {
  1092.     FILE *fddsk;            /* Disk file pointer */
  1093.     char    cmnd[1];            /* Command character */
  1094.     int r;
  1095.     int nor = 0;
  1096.  
  1097.     sscanf(msg,"%s %s %s %s %s %s %o",
  1098.         cmnd, srcnam, dstnam, who, flags, temp, &mode);
  1099.  
  1100.     ulog(-1, "REQUESTED %s", msg);
  1101.     munge_filename(dstnam, dstnam);           /* Translate to local name */
  1102.     strcpy (temp, TmpFileName(dstnam));       /* Create a handy temp file */
  1103.  
  1104.     if (SecurityDisallow(dstnam, 'w')) {
  1105.     ulog(-1, "REQUEST FAILED -- SECURITY");
  1106.     if (yesno('S', 0, 4))
  1107.         return FAIL;
  1108.     return SUCCESS;
  1109.     }
  1110.     if (SecurityDisallow(dstnam, 'c') > 0) {
  1111.     ulog(-1, "REQUEST FAILED -- SECURITY, REMOTE TRIED TO SEND");
  1112.     ulog(-1, "US A COMMAND FILE: %s, FILE COPIED TO T:Bad-Cmd", dstnam);
  1113.     strcpy(dstnam, "T:Bad-Cmd");
  1114.     nor = 1;
  1115.     }
  1116.  
  1117.     /* FIXME: deal with file modes now that we fopen. */
  1118.  
  1119.     LockFile(temp);
  1120.  
  1121.     fddsk = fopen(temp, "wb" /*, mode|0600 */);
  1122.     if (fddsk == NULL) {
  1123.     UnLockFile(temp);
  1124.     /* Can't open file -- send error response */
  1125.     if (debug > 0) {
  1126.         printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
  1127.         temp,
  1128.         dstnam,
  1129.         errno
  1130.         );
  1131.     }
  1132.     ulog(-1, "REQUEST FAILED -- TEMP FILE");
  1133.     if (yesno('S', 0, 4))
  1134.         return FAIL;
  1135.     return SUCCESS;
  1136.     }
  1137.  
  1138.     /* FIXME: Are the above permissions right?? */
  1139.     /* FIXME: Should we create directories for the file? */
  1140.  
  1141.     if (yesno('S',1, 0)) {  /* Say yes */
  1142.     fclose(fddsk);
  1143.     unlink(temp);
  1144.     UnLockFile(temp);
  1145.     return 1;
  1146.     }
  1147.     r = receive_file(fddsk, temp, dstnam, srcnam, nor);
  1148.     UnLockFile(temp);
  1149.     return(r);
  1150. }
  1151.  
  1152. /*
  1153.  *  SLAVE MODE, Master wants us to send a file to it
  1154.  *
  1155.  *  SECURITY:    If file is not in list of allowed directories
  1156.  *        disallow transfer.  UUSPOOL:   is always in the
  1157.  *        list.
  1158.  *
  1159.  *  0 = sucess
  1160.  */
  1161.  
  1162. host_receive_file(msg)
  1163. char  *msg;
  1164. {
  1165.     FILE *fddsk;     /* Disk file descriptor */
  1166.     int x;
  1167.     char    cmnd[1];            /* Command character */
  1168.  
  1169.     ulog(-1, "REQUESTED %s", msg);
  1170.  
  1171.     sscanf(msg,"%s %s %s",cmnd,srcnam,dstnam);
  1172.     munge_filename(srcnam, temp);
  1173.  
  1174.     if (SecurityDisallow(srcnam, 'r')) {
  1175.     ulog(-1, "COPY FAILED -- SECURITY");
  1176.     if (yesno('S', 0, 4))
  1177.         return FAIL;
  1178.     return SUCCESS;
  1179.     }
  1180.  
  1181.     fddsk = fopen(temp, "rb");              /* Try to open the file */
  1182.     if (fddsk == NULL) {
  1183.     /* File didn't open, sigh. */
  1184.     if (debug > 0) {
  1185.         printf("Cannot open file %s (%s) for reading, errno=%d\n",
  1186.         temp, srcnam, errno
  1187.         );
  1188.     }
  1189.     ulog(-1, "DENIED CAN'T OPEN %s", temp);
  1190.     if (yesno('R', 0, 2))
  1191.         return 1;
  1192.     return 0;
  1193.     }
  1194.  
  1195.     if (yesno('R',1, 0)) {  /* Say yes */
  1196.     fclose(fddsk);
  1197.     return 1;
  1198.     }
  1199.  
  1200.     x = send_file(fddsk);
  1201.  
  1202.     switch (x) {
  1203.     default:
  1204.     return x;
  1205.     case COPYFAIL:
  1206.     /* We don't care if the copy failed, since the master
  1207.        asked for the file and knows the result. */
  1208.     return SUCCESS;
  1209.     }
  1210.     return 1;
  1211. }
  1212.  
  1213. /*
  1214.  *  MASTER MODE, We want to send a file.
  1215.  *
  1216.  *  Return FAIL, SUCCESS, or COPYFAIL.
  1217.  *
  1218.  *  SUCCESS is returned either if the file was not found locally (local
  1219.  *  error, and the queued transfer should be flushed) or if it was moved
  1220.  *  successfully.  COPYFAIL indicates that the queued transfer should be
  1221.  *  left queued, and later retried.  FIXME, there are several failure points
  1222.  *  in the transaction (see Protocol.doc) and we need finer control here.
  1223.  */
  1224.  
  1225. int
  1226. local_send_file(workstr, delmeflag)
  1227. char *workstr;
  1228. int *delmeflag;
  1229. {
  1230.     static char buf[MAXMSGLEN];    /* Used for both xmit and receive */
  1231.     FILE *fddsk;        /* Disk file descriptor */
  1232.     int res;            /* Result and file removal status */
  1233.  
  1234.     *delmeflag = 0;
  1235.  
  1236.     /* WHY are temp and srcnam switched?  FIXME!  And no notify? */
  1237.  
  1238.     sprintf(buf,"S %s %s %s %s %s 0%o %s",
  1239.     temp, dstnam, who, flags, srcnam, mode, who
  1240.     );
  1241.  
  1242.     ulog(-1, "REQUEST %s", buf);
  1243.  
  1244.     if (strchr(flags, 'c')) {
  1245.     munge_filename(srcnam, temp);
  1246.     } else {
  1247.     munge_filename(temp, temp);
  1248.     }
  1249.     LockFile(temp);
  1250.     fddsk = fopen(temp, "rb");
  1251.     if (fddsk == NULL) {
  1252.     UnLockFile(temp);
  1253.     /* FIXME -- handle queued request for nonexistent file */
  1254.     if (debug > 0)
  1255.         printf("Can't open file %s (%s), errno=%d\n",
  1256.         temp,
  1257.         srcnam,
  1258.         errno
  1259.         );
  1260.     ulog(-1, "NOT FOUND %s", temp);
  1261.     /* return COPYFAIL;*/
  1262.     return SUCCESS;     /*    assume file previously sent */
  1263.     }
  1264.  
  1265.     /* Tell the other side we want to send this file */
  1266.  
  1267.     if (wrmsg(buf) != SUCCESS) {
  1268.     DEBUG(0, "problem sending request\n", 0);
  1269.     fclose(fddsk);
  1270.     UnLockFile(temp);
  1271.     return FAIL;
  1272.     }
  1273.  
  1274.     /* See what they have to say about it */
  1275.  
  1276.     if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
  1277.     fclose(fddsk);
  1278.     UnLockFile(temp);
  1279.     return FAIL;
  1280.     }
  1281.     if ((buf[0] != 'S') || (buf[1] != 'Y')) {
  1282.     ulog(-1, "REQUEST DENIED %s", buf);
  1283.     fclose(fddsk);
  1284.     UnLockFile(temp);
  1285.     return FAIL;
  1286.     }
  1287.     res = send_file(fddsk); /* FAIL, SUCCESS, or COPYFAIL */
  1288.  
  1289.     /* Delete the source file if it was just a copy */
  1290.  
  1291.     if (res != SUCCESS) {
  1292.     UnLockFile(temp);
  1293.     return res;
  1294.     }
  1295.     if (strchr(flags, 'c')) {   /* If copied direct from source */
  1296.     UnLockFile(temp);
  1297.     return res;        /* ...just return. */
  1298.     }
  1299.     *delmeflag = 1;
  1300.     UnLockFile(temp);
  1301.  
  1302.     return res;
  1303. }
  1304.  
  1305. /*
  1306.  *  MASTER MODE, We wish to receive a specific file so we ask for it
  1307.  *
  1308.  *  Return 0 = success
  1309.  */
  1310.  
  1311. int
  1312. local_receive_file()
  1313. {
  1314.     static char buf[MAXMSGLEN];
  1315.     FILE *fddsk;            /* Disk file pointer */
  1316.     int r;
  1317.  
  1318.     /* FIXME, test dest file access before we ask for it. */
  1319.  
  1320.     sprintf(buf,"R %s %s %s %s %s 0%o %s",
  1321.     srcnam, dstnam, who, flags, temp, mode, who
  1322.     );
  1323.  
  1324.     munge_filename(dstnam, dstnam);           /* tlate to local name      */
  1325.     strcpy (temp, TmpFileName(dstnam));       /* Create a handy temp file */
  1326.  
  1327.     /* FIXME: deal with file modes now that we fopen. */
  1328.     /* FIXME: Are the above permissions right?? */
  1329.     /* FIXME: Should we create directories for the file? */
  1330.  
  1331.     LockFile(temp);
  1332.     fddsk = fopen(temp, "wb" /*, mode|060 */);
  1333.  
  1334.     if (fddsk == NULL) {
  1335.     UnLockFile(temp);
  1336.     /* Can't open temp file -- send error response */
  1337.     if (debug > 0) {
  1338.         printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
  1339.         temp,
  1340.         dstnam,
  1341.         errno
  1342.         );
  1343.     }
  1344.     ulog(-1, "REQUEST FAILED -- TEMPFILE");
  1345.     return FAIL;
  1346.     }
  1347.  
  1348.     ulog(-1, "REQUEST %s", buf);
  1349.     if (wrmsg(buf) != SUCCESS) {
  1350.     fclose(fddsk);
  1351.     UnLockFile(temp);
  1352.     printf("uucico: problem sending request\n");
  1353.     return FAIL;
  1354.     }
  1355.  
  1356.     /* See what the other side has to say about it */
  1357.  
  1358.     if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
  1359.     fclose(fddsk);
  1360.     UnLockFile(temp);
  1361.     return FAIL;
  1362.     }
  1363.     if ((buf[0] != 'R') || (buf[1] != 'Y')) {
  1364.     ulog(-1, "REQUEST DENIED %s", buf);
  1365.     fclose(fddsk);
  1366.     UnLockFile(temp);
  1367.     return SUCCESS; /* FIXME, should do something more here */
  1368.     }
  1369.  
  1370.     r = receive_file(fddsk, temp, dstnam, srcnam, 0);
  1371.     UnLockFile(temp);
  1372.     return(r);
  1373. }
  1374.  
  1375. /*
  1376.  *  General receive file
  1377.  */
  1378.  
  1379. int
  1380. receive_file(fddsk, temp, dstnam, srcnam, norename)
  1381. FILE *fddsk;
  1382. char    *temp, *dstnam, *srcnam;
  1383. {
  1384.     int status;
  1385.     int error = 0;            /* No errors so far */
  1386.  
  1387.     if (rddata(fddsk) != SUCCESS)
  1388.     error++;
  1389.     status = fclose(fddsk);         /* Make sure the data got here */
  1390.     if (status != 0) {
  1391.     error++;
  1392.     DEBUG(0, "fclose errno=%d\n", errno);
  1393.     }
  1394.  
  1395.     /*
  1396.      *    Move the file from its temp location to its real location,
  1397.      *    This needs to be able to copy a file if a simple rename
  1398.      *    does not suffice.  Should create directories if necesary.
  1399.      *    should use source ]name if target is a directory (i.e. no
  1400.      *    target source name
  1401.      */
  1402.  
  1403.     unlink(dstnam);
  1404.  
  1405.     if (norename)       /*  for security redirect   */
  1406.     status = 0;
  1407.     else
  1408.     status = rename(temp, dstnam);
  1409.  
  1410.     if (status != 0) {
  1411.     error++;
  1412.     if (debug > 0) {
  1413.         printf("Cannot rename file %s to %s, errno=%d\n",
  1414.         temp, dstnam, errno);
  1415.     }
  1416.     }
  1417.  
  1418.     ulog(-1, "COPY %s", error ? "FAILED": "SUCCEEDED");
  1419.  
  1420.     if (yesno('C', error == 0, 5))  /* Send yes or no */
  1421.     return FAIL;
  1422.  
  1423.     return SUCCESS;
  1424. }
  1425.  
  1426. /*
  1427.  * general file send routine
  1428.  * Return SUCCESS, FAIL, or COPYFAIL.
  1429.  */
  1430.  
  1431. int
  1432. send_file(fddsk)
  1433. FILE *fddsk;     /* Disk file pointer */
  1434. {
  1435.     static char ansbuf[MAXMSGLEN];
  1436.  
  1437.     if (wrdata(fddsk) != SUCCESS) {
  1438.     fclose(fddsk);
  1439.     return COPYFAIL;
  1440.     }
  1441.     fclose(fddsk);
  1442.  
  1443.     /* Await the "CY" or "CNddd" packet, and toss it. */
  1444.  
  1445.     while (1) {
  1446.     if (rdmsg(ansbuf, MAXMSGLEN) != SUCCESS)
  1447.         return COPYFAIL;
  1448.     if (ansbuf[0] != 'C') {
  1449.         DEBUG(0,"\nDidn't get 'CY' or 'CN', got %s\n", ansbuf);
  1450.         /* and loop looking for C message */
  1451.     } else if (ansbuf[1] == 'Y') {
  1452.         ulog(-1, "REQUESTED %s", ansbuf);
  1453.         return SUCCESS;
  1454.     } else {
  1455.         ulog(-1, "COPY FAILED %s", ansbuf);
  1456.         return COPYFAIL;
  1457.     }
  1458.     }
  1459.     return COPYFAIL;
  1460. }
  1461.  
  1462.